module Duplicate

import Crawl;
import IO;
import List;
import String;
import Volume;  
import Relation;
import Set;
import Map;
import lang::java::jdt::JavaADT;
import lang::java::jdt::Java;
import lang::java::jdt::JDT;
import util::Math;

//Used in getDuplicates(loc location);
map[str, rel[int, int]] globDups =();

public int getDuplicatesList(list[loc] locations)
{
	int returnVal = 0;
	for(loc l <- locations)
	{
		returnVal += getDuplicates(l);
	}
	return returnVal;
}


public int getDuplicates(loc location)
{
	set[int] duplicates = {};
	if(globDups == ())
	{
		//println("Creating DupList");
		dups = index(getBlocks(getLinesFromMethods()));		
		// Get all indexes that have one ore more occurances. 
		globDups = (dup : dups[dup] | dup <- dups, size(dups[dup]) > 1);
	}
	
	str allLines = remExtras(readFile(location));
	listLines = split("\n", allLines);
	trimmedLines = [trim(line)  | line <- listLines];
	fileBlocks = getBlocks(trimmedLines);
	
	for(tuple[str,tuple[int,int]] block <- fileBlocks)
	{
	 	if(block[0] in globDups)
	 	{
	 		for(int i <- [block[1][0]..block[1][1]])
			{
				duplicates += i;
			} 
	 	}
	} 
	return size(duplicates);
}

public list[str] getLinesFromMethods()
{
	str allLines ="";
	fm = extractProject(|project://SmallSql|);
	//fm = extractProject(|project://hsqldb|);
	BindingRel methods = fm@methodDecls;
	
	visit(methods) {
	case <loc l, Entity e> : {  
		allLines += readFile(l);
		}
	}
	allLines = remExtras(allLines);

	//Trim lines and return them. Function takes very long when stated as : return [trim(line)  | line <- strToList(allLines)];
	//listLines = strToList(allLines);
	listLines = split("\n", allLines);
	trimmedLines = [trim(line)  | line <- listLines];
	return trimmedLines;
}

public rel[str,tuple[int,int]] getBlocks(list[str] lines)
{	
	int amountLines = size(lines);
	rel[str,tuple[int,int]] duplicates = {};
	//Files smaller than 6 have no duplicates.
	if(amountLines < 6)
	{
		return duplicates;
	}
	for(int i <- [0..amountLines -6])
	{
		duplicates += <(lines[i] + lines[i + 1] + lines[i + 2] + lines[i + 3] + lines[i + 4] + lines[i + 5]) , <i,i+5>>; 	 	
	}	
	return duplicates;
}

public int countDuplicates(rel[str,tuple[int,int]] input)
{		
	dups = index(input);		
	// Get all indexes that have one ore more occurances. 
	duplications = (dup : dups[dup] | dup <- dups, size(dups[dup]) > 1);
	//Add them to a set to get unique nrs. 
	setDups = {};
	for(dup <- duplications)
	{
		relat = duplications[dup];
		for(tup <- relat)
		{
			for(int i <- [tup[0]..tup[1]])
			{
				setDups += i;
			}
		}
	}
	return size(setDups);
}


//There is probably a better way to do this. 
public list[str] strToList(str input)
{	
	writeFile(|file:///C:/temp.txt|, input);
	return readFileLines(|file:///C:/temp.txt|);
}

public str getRanking()
{
	lines = getLinesFromMethods(); 
	duplicates = countDuplicates(getBlocks(lines));
	percDuplicated = toReal(duplicates) / toReal(size(lines));
	println("totalSize : <size(lines)> amountDuplicated: <duplicates> percentage: <percDuplicated>");
	
	if (percDuplicated <= 0.03)
 		return "++";
 	else if (percDuplicated <= 0.05)	
 		return "+";
 	else if (percDuplicated <= 0.10)
 		return "o";
 	else if (percDuplicated <= 0.20)
 		return "-";
 	else
 		return "--";	
}
